#include "plaintext_map.h"
#include <tr1/unordered_map>
#include <stdlib.h>
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
using namespace std::tr1;
struct elementHash{
	inline size_t operator() (element_wrap t) const
	{
	int n= element_length_in_bytes(t.element);
	unsigned char* data = (unsigned char*)malloc(n*sizeof(char));
	element_to_bytes(data,t.element);	
	long val =0;
	for (int i=0; i<n; i++){
		val = 5*val + data[i] + 31;
	}
	return size_t(val);
	}
};

struct equalElement{
	inline bool operator()(element_wrap t1, element_wrap t2) const { 
	if (!element_cmp(t1.element,t2.element))
		return true;
	else 
		return false;
	}
};

unordered_map<element_wrap,int, elementHash, equalElement> mapElement;
unordered_map<int,element_wrap> mapPlaintext; 
element_t hv;
unsigned char* testVal;
void plaintext_map_initialize(int max, pairing_t p){

	//init
	element_init_GT(hv,p);
	element_random(hv);
	
	element_t exp;
	element_init_Zr(exp,p);
	element_t val;
	element_init_GT(val,p);
	for (int i=0; i<max; i++){
		element_set_si(exp,i);
		element_pow_zn(val,hv,exp);
		element_wrap val1;
		element_init_GT(val1.element,p);
		element_set(val1.element,val);
		mapElement[val1] = i; 	
		mapPlaintext[i] = val1;
	}
}

//also hide i using a mask
int toElement(element_t t, int i, element_t mask, pairing_t p){
	element_init_GT(t,p);
	element_t sum,ie;
	element_init_Zr(sum,p);
	element_init_Zr(ie,p);
	element_set_si(ie,i);

	element_add(sum,ie,mask);
	element_pow_zn(t,hv,sum);
	
	return 1;
}

int toPlaintext(element_t t, element_t mask, pairing_t p){
	element_wrap et;
	element_init_GT(et.element,p);

	element_t unmask, pt;
	element_init_GT(unmask, p);
	element_init_GT(pt,p);
	element_pow_zn(unmask,hv,mask);
	element_div(pt,t,unmask);
	
	element_set(et.element,pt);

	unordered_map<element_wrap, int, elementHash, equalElement>::const_iterator it =
	mapElement.find(et);
		
	if (it==mapElement.end()){
		cout << "Did not find anything" << endl;
		return -1;
	}
	return mapElement[et];

}
